﻿using MongoDB.Bson;
using Newtonsoft.Json;
using Sustainalytics.BusinessResearchProductStates.Entities.ResearchState;
using Sustainalytics.Common.Services;
using Sustainalytics.Entities;
using Sustainalytics.ScreeningTool.BL;
using System.Collections.Generic;
using System.Linq;

namespace Sustainalytics.ScreeningTool.Service.Map
{
    public class RunResultMap : IMap<RunResultDto, BsonDocument>
    {
        public RunResultDto Map(BsonDocument source)
        {
            if (source == null)
                return null;

            var runResultDto = new RunResultDto
            {
                Id = source["_id"].AsGuid,
                FilterId = source["FilterId"].AsGuid,
                IsValid = (ResultIsValid)(source["IsValid"].AsInt32)
            };

            if (source["Criteria"] != null)
                runResultDto.Criteria = GetCriteria(source).ToList();

            if (source.Contains("CompanyName"))
                runResultDto.CompanyName = source["CompanyName"].AsString;

            if (source.Contains("CompanyNameUrlFriendly"))
                runResultDto.CompanyNameUrlFriendly = source["CompanyNameUrlFriendly"].AsString;

            if (source.Contains("SecurityId"))
                runResultDto.SecurityId = source["SecurityId"].AsString;

            if (source.Contains("CapitalIqId"))
                runResultDto.CapitalIqid = source["CapitalIqId"].AsInt32;

            if (source.Contains("SecurityIdentifier"))
                runResultDto.SecurityIdentifier = source["SecurityIdentifier"].AsString;

            if (source.Contains("CustomSecurityIdentifierName"))
                runResultDto.CustomSecurityIdentifierName = source["CustomSecurityIdentifierName"].AsString;

            return runResultDto;
        }

        private IEnumerable<CriteriaResultDto> GetCriteria(BsonDocument source)
        {
            var criteria = JsonConvert.DeserializeObject<List<CriteriaResultOutput>>(source["Criteria"].AsString);

            foreach (var criteriaResultOutput in criteria.OrderBy(p => p.Order))
            {
                if (!criteriaResultOutput.IsTemporary)
                {
                    if (criteriaResultOutput.StringValue != "No Access")
                    {
                        var formatedCriteriaValue = CriteriaValueFormatter.FormatCriteriaValue(source, criteriaResultOutput);
                        if (formatedCriteriaValue != null)
                        {
                            criteriaResultOutput.StringValue = formatedCriteriaValue;
                        }
                    }
                    yield return Map<CriteriaResultDto, CriteriaResultOutput>(criteriaResultOutput);
                }
            }
        }

        public TDestination Map<TDestination, TSource>(TSource source)
        {
            var mapper = ServiceProvider.Single<IMap<TDestination, TSource>>();
            return mapper.Map(source);
        }
    }
}
